/*
 * MsjReceptorMid.cpp
 *
 *  Created on: 12/02/2010
 *      Author: San Martín, Matías I.
 */

#include "MsjReceptorMid.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#include "../../Framework/IO/log.h"
#include "../../Framework/Common/utiles.h"
#include "../../Framework/Excepciones/InicializacionExcepcion.h"
#include "../../Aplicacion/Common/Mensajes/MensajeAplicacion.h" //TODO CORREGIR
#include "../Comunicaciones/MiddlewareCliente.h"

using namespace framework::io;

MsjReceptorMid::~MsjReceptorMid() {
}

void MsjReceptorMid::handlerAvisoRegistrarPipe(int signal)
{
	logger << LogType::LOG_DEBUG_0 <<"Recibida señal para registrar pipe. " << logger.endl;
	//si se recibio una señal de que hay datos por registrar
	MsjReceptorMid & mid = MsjReceptorMidSingleton::instance();

	//lee la info de los datosRegistro
	IdPlaneta idPlanetaRegistrar;
	idPlanetaRegistrar.loadFromMensaje
			((*mid._datosRegitro)->idPlaneta);

	//llama a registrarPipe
	mid.registrarPipe((*mid._datosRegitro)->nombrePipe,idPlanetaRegistrar);

	//libera el semaforo de lectura de datos
	mid._semLeyendoDatos->signal();

}

void MsjReceptorMid::handlerDetencion(int signal)
{
	MsjReceptorMidSingleton::instance().stop();
}

void MsjReceptorMid::inicializar(MiddlewareIO* receptor,
								Semaphore* semLeyendoDatos,
									t_sharedRegistro* datosRegitro)
{
	logger.set_pname("Planeta/MsjReceptorMid");
	logger << LogType::LOG_DEBUG_0 <<"inicializando MsjReceptorMid..." << logger.endl;

	if (!(*semLeyendoDatos && *datosRegitro && receptor))
	{
		throw new InicializacionExcepcion("Error al inicializar el MsjReceptorMid"
				", parametros de inicializacion incorrectos.");
	}
	_semLeyendoDatos = semLeyendoDatos;
	_datosRegitro = datosRegitro;
	_receptor = receptor;

	//registrar manejador de señales
	Utiles::registrar_signal(SIG_NOTIFICACION, handlerAvisoRegistrarPipe);

	//se registra el signal de interrupcion
	Utiles::registrar_signal(SIGINT, handlerDetencion);

	logger << "MsjReceptorMid inicializado!" << logger.endl;
}

void MsjReceptorMid::start()
{
	char datos[MAX_DATOS];
	_ejecutar = true;

	logger << "Inicia ejecucion." << logger.endl;
	while (_ejecutar)
	{

		//espero por mensaje
		logger << LogType::LOG_DEBUG_0 <<"esperando mensaje..." << logger.endl;
		if (_receptor->recv(datos))
		{
			//deserializo el mensaje
			//TODO CORREGIR DEPENDENCIA
			aplicacion::MensajeAplicacion msj;
			msj.loadFromArray(reinterpret_cast<uint8_t*>(datos));
			logger << LogType::LOG_DEBUG_0 <<"Recibido mensaje: " << msj << logger.endl;

			//busco el pipe asociado al destino
			IdPlaneta destino;
			msj.getEncabezado().getDestino(destino);
			t_mapIdPlaneta_Pipe::iterator pos = _mapPipes.find(destino);
			if (pos != _mapPipes.end())
			{
				//escribo los datos en el pipe asociado al destino
				msj.save(pos->second);
			}else{
				logger << LogType::LOG_WARNING <<"Se ignora mensaje recibido, destino desconocido:"
						<< destino << logger.endl;
			}
		}//recepcion de mensaje
	}//ciclo de ejecucion

	logger << "Detenido" << logger.endl;
}

void MsjReceptorMid::stop()
{
	logger << LogType::LOG_DEBUG_0 <<"Deteniendo..." << logger.endl;
	_ejecutar = false;
}

int MsjReceptorMid::crearPipe(const std::string& nombrePipe)
{

	if (mkfifo(nombrePipe.c_str(),0666) == -1 && errno != EEXIST)
	{
		logger << LogType::LOG_ERROR <<"Error al crear el pipe asociado al path '"
				<< nombrePipe << "' : " << logger.err << logger.endl;
	}

	//TEST: CAMBIAR PARA PRUEBAS DE MIDDLEWARE SOLO (evita que se bloquee el pipe pq no tiene el otro extremo abierto)
	//int pipe = open(nombrePipe.c_str(),O_RDWR);

	//se abre el pipe para escritura
	int pipe = open(nombrePipe.c_str(),O_WRONLY);

	if (pipe == -1)
	{
		logger << LogType::LOG_ERROR <<"Error al abrir el pipe asociado al path '"
				<< nombrePipe << "' : " << logger.err << logger.endl;
	}

	return pipe;
}

void MsjReceptorMid::registrarPipe(const std::string& nombrePipe,const IdPlaneta& idPlaneta)
{
	//creo el pipe
	int pipe = this->crearPipe(nombrePipe);
	if (pipe > 0)
	{
		logger << LogType::LOG_DEBUG_0 <<"Se registra el pipe '" << nombrePipe
				<< "' asociado al destino '" << idPlaneta << "'." << logger.endl;
		this->_mapPipes[idPlaneta] = pipe;
	}
}
